package com.bcx.wind.workflow.imp.cmd.corecmd;

import com.bcx.wind.workflow.access.QueryFilter;
import com.bcx.wind.workflow.core.constant.OrderStatus;
import com.bcx.wind.workflow.core.constant.OrderType;
import com.bcx.wind.workflow.core.flow.NodeModel;
import com.bcx.wind.workflow.core.flow.node.*;
import com.bcx.wind.workflow.core.lock.Lock;
import com.bcx.wind.workflow.entity.*;
import com.bcx.wind.workflow.errorcontext.WindError;
import com.bcx.wind.workflow.interceptor.Command;
import com.bcx.wind.workflow.interceptor.CommandContext;
import com.bcx.wind.workflow.pojo.Task;
import com.bcx.wind.workflow.pojo.Wind;
import com.bcx.wind.workflow.pojo.WindConfig;
import com.bcx.wind.workflow.pojo.WindUser;
import com.bcx.wind.workflow.support.Assert;
import com.bcx.wind.workflow.support.JsonHelper;
import com.bcx.wind.workflow.support.ObjectHelper;
import com.bcx.wind.workflow.support.TimeHelper;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static com.bcx.wind.workflow.message.ErrorCode.*;

/**
 * 工作流核心命令父实现
 *
 * @author zhanglei
 */
abstract class BaseCommand implements Command<Wind> {

    /**
     * 执行数据
     */
    protected CommandContext commandContext;

    /**
     * 所有配置数据
     */
    protected List<WindProcessConfig> configList;


    /**
     * 所有任务
     */
    protected List<WindTask>  allTasks;

    /**
     * 所有流程实例
     */
    protected List<WindOrder> allOrders;

    /**
     * 所有任务审批人
     */
    protected List<WindTaskActor> allTaskActors;


    /**
     * 实际执行
     *
     * @return  工作流实例信息
     */
    public abstract Wind execute();


    @Override
    public Wind executor(CommandContext context) {
        try {
            this.commandContext = context;
            //添加线程本地wind
            this.commandContext.setWind(new Wind());
            Wind wind =  this.execute();
            //删除线程本地wind
            this.commandContext.removeWind();
            return wind;
        }catch (Exception e){
            context.log(e);
            return null;
        }
    }


    protected Wind wind(){
        return this.commandContext.getWind();
    }


    /**
     * 当前流程所有配置
     * @param processId  流程定义ID
     */
    void getConfigList(String processId){
        List<WindProcessConfig> configs = commandContext.getConfiguration()
                .getProcessConfig(processId);
        if(ObjectHelper.isEmpty(configs)){
            QueryFilter filter = new QueryFilter()
                    .setProcessId(processId);
            configs = commandContext.access().selectProcessConfigList(filter);
            Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND,configs,this.wind().getWindProcess().getProcessName());
        }
        this.configList = configs;
    }


    WindConfig buildWindConfig(WindProcessConfig config){
        return new WindConfig()
                .setNodeId(config.getNodeId())
                .setProcessId(config.getProcessId())
                .setProcessName(config.getProcessName())
                .setConfigName(config.getConfigName())
                .setBusinessConfig(config.getBusinessConfig())
                .setNodeConfig(config.getNodeConfig())
                .setApproveUser(config.getApproveUser());
    }



    Task buildCurNodeConfig(String curNodeId, WindTask windTask){
        //当前节点
        NodeModel curNode = this.wind().getWindProcess().processModel().getTaskModel(curNodeId);

        if(!(curNode instanceof TaskNode)){
            return null;
        }
        WindProcessConfig config = ObjectHelper.getNodeConfig(this.configList,curNodeId,this.wind().getArgs());
        Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND,config,
                this.wind().getWindProcess().getProcessName(),curNodeId);
        assert config != null;
        Task task = new Task()
                .setNodeId(curNodeId)
                .setNodeName(curNode.nodeName())
                .setTaskNode(curNode)
                .setWindTask(windTask)
                .setConfig(buildWindConfig(config));
        //可以自由提交的节点
        buildSubmitTasks(curNode,task);
        //可以自由驳回的节点
        buildRejectTasks(task);
        //默认提交路线设置
        buildSubmitPath(curNode,task);
        return task;
    }

    private void  buildSubmitPath(NodeModel curNode,Task curTask){
        List<Path> paths = curNode.path();
        //任务节点只有一条路线，获取第一条路线
        Path path = paths.get(0);
        NodeModel nextNode = path.getNextNode();
        //如果路线指向任务节点
        if(nextNode instanceof TaskNode){
            addPaths(path,nextNode,curTask);
            return;
        }

        //如果路线指向子流程
        if(nextNode instanceof RouterNode){
            nextNode = ((RouterNode) nextNode).getFirstTaskNode();
            addPaths(path,nextNode,curTask);
            return;
        }


        //如果指向自定义节点
        if(nextNode instanceof Custom){
            nextNode = nextNode.nextTask().get(0);
            addPaths(path,nextNode,curTask);
            return;
        }

        //如果指向分支节点
        if(nextNode instanceof OrNode || nextNode instanceof AndNode || nextNode instanceof DynaNode){
            paths = nextNode.path();
            for(Path  p : paths){
                nextNode = p.getNextNode();
                nextNode = nextNode instanceof Custom ? nextNode.nextTask().get(0) : nextNode;
                addPaths(path,nextNode,curTask);
            }
            return;
        }

        //如果指向订阅节点
        if(nextNode instanceof ScribeNode){
            paths = nextNode.path();
            for(Path p : paths){
                nextNode = p.getNextNode();
                if(nextNode instanceof ScribeTaskNode){
                    continue;
                }
                addPaths(p,nextNode,curTask);
            }
            return;
        }

        /**
         * 还有很多的是请
         * 这个方法主要是用来作为一个基类来使用的其实
         */
        //如果指向决策节点
        if(nextNode instanceof DiscNode){
            paths = nextNode.path();
            for(Path  p : paths){
                nextNode = p.getNextNode();
                nextNode = nextNode instanceof Custom ? nextNode.nextTask().get(0) : nextNode;
                //决策后存在分支
                if(nextNode instanceof OrNode || nextNode instanceof AndNode || nextNode instanceof DynaNode){
                    List<Path> ps  = nextNode.path();
                    for(Path  p1 : ps){
                        nextNode = p1.getNextNode();
                        nextNode = nextNode instanceof Custom ? nextNode.nextTask().get(0) : nextNode;
                        addPaths(p,nextNode,curTask);
                    }
                    continue;
                }
                addPaths(p,nextNode,curTask);
            }
        }


    }



    private void addPaths(Path path,NodeModel nextNode,Task curTask){
        Assert.isTrue("submitPath nextNode is not Task!",!(nextNode instanceof TaskNode));
        Task task = new Task(path.getNodeId(),path.getNodeName());
        List<Task> submitPath = curTask.getSubmitPath();
        if(submitPath.contains(task)){
            Task t = submitPath.stream().filter(ta->ta.getNodeId().equals(task.getNodeId()))
                    .findFirst().orElseThrow(()->WindError.error("error"));
            t.getSubmitTasks().add(getPathToTask(nextNode,curTask));
            return;
        }

        task.getSubmitTasks().add(getPathToTask(nextNode,curTask));
        curTask.getSubmitPath().add(task);
    }



    private Task  getPathToTask(NodeModel nodeModel,Task curTask){
        List<Task> canSubmitTasks = curTask.getCanSubmitTasks();
        return  canSubmitTasks.stream().filter(t->t.getNodeId().equals(nodeModel.nodeId()))
                .findFirst().orElseThrow(()->WindError.error("submitTask not found! "));
    }


    /**
     * 可提交节点 以及配置
     *
     * @param curNode  当前节点
     * @param curTask  当前任务
     */
    private void buildSubmitTasks(NodeModel curNode,Task curTask){
        List<NodeModel> nextNodes = curNode.nextAllTask();
        for (NodeModel next : nextNodes) {
            WindProcessConfig nextConfig = ObjectHelper.getNodeConfig(this.configList, next.nodeId(), this.wind().getArgs());
            Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND, nextConfig,
                    this.wind().getWindProcess().getProcessName(), next.nodeId());
            assert nextConfig != null;
            Task nextTask = new Task()
                    .setNodeId(next.nodeId())
                    .setNodeName(next.nodeName())
                    .setTaskNode(next)
                    .setConfig(buildWindConfig(nextConfig));
            curTask.getCanSubmitTasks().add(nextTask);
        }
    }



    /**
     * 可驳回节点以及配置
     * @param curTask  当前任务
     */
    private void buildRejectTasks(Task curTask){
        //NO CODE
        List<String> rejectNodeIds = getWindActHistory();
        //可驳回节点
        List<NodeModel> canRejects = new LinkedList<>();
        for(String nodeId : rejectNodeIds){
            NodeModel nodeModel = wind().getWindProcess().processModel().getTaskModel(nodeId);
            canRejects.add(nodeModel);
        }

        for(NodeModel pre : canRejects){
            WindProcessConfig preConfig = ObjectHelper.getNodeConfig(this.configList, pre.nodeId(), this.wind().getArgs());
            Assert.notEmptyError(PROCESS_CONFIG_NOT_FOUND, preConfig,
                    this.wind().getWindProcess().getProcessName(), pre.nodeId());
            Task nextTask = new Task()
                    .setNodeId(pre.nodeId())
                    .setNodeName(pre.nodeName())
                    .setTaskNode(pre)
                    .setConfig(buildWindConfig(preConfig));
            if(!pre.nodeId().equals(curTask.getNodeId())) {
                curTask.getCanRejectTasks().add(nextTask);
            }
        }

    }


    /**
     * 获取已经审批的历史，通过这些历史查询可以驳回的节点
     * @return    历史
     */
    private List<String> getWindActHistory(){
        QueryFilter filter = new QueryFilter()
                .setOrderId(wind().getWindOrder().getId());

        List<WindActHistory> actHistories =  this.commandContext.access().selectActiveHistoryList(filter);
        return actHistories.stream()
                .map(WindActHistory::getTaskName).distinct().collect(Collectors.toList());
    }


    Lock getLock(){
        return commandContext.getConfiguration().getLock();
    }



    /**
     * 当前流程实例下所有任务
     */
    protected   List<WindTask>  tasks(String orderId){
        QueryFilter filter =new QueryFilter()
                .setOrderId(orderId);
        return commandContext.access().selectTaskInstanceList(filter);
    }


    /**
     * 添加当前流程相关数据到撤销数据中
     */
    protected   void  addRevokeData(WindTask task){
        //查询所有流程实例数据
        allOrderInstance();
        //查询所有任务,以及审批人
        allTaskInstance();

        WindRevokeData data = new WindRevokeData()
                .setId(ObjectHelper.primaryKey())
                .setOrderId(this.wind().getWindOrder().getId())
                .setProcessId(this.wind().getWindProcess().getId())
                .setTaskName(task.getTaskName())
                .setTaskDisplayName(task.getDisplayName())
                .setActorId(wind().getUser().getUserId())
                .setOperate(this.wind().getOperate().name())
                .setSuggest(this.wind().getSuggest())
                .setOperateTime(TimeHelper.nowDate())
                .setWindOrder(JsonHelper.toJson(this.allOrders))
                .setWindTask(JsonHelper.toJson(this.allTasks))
                .setWindTaskActor(JsonHelper.toJson(this.allTaskActors))
                .setCreateTime(TimeHelper.nowDate());
        //添加
        this.commandContext.access().insertWindRevokeData(data);
    }


    /**
     * 所有任务以及审批人
     */
    private void  allTaskInstance(){
        //查询任务实例
        String orderId = this.wind().getWindOrder().getId();
        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId);
        this.allTasks  =  this.commandContext.access().selectTaskInstanceList(filter);

        //查询任务审批人
        List<String> taskIds = this.allTasks.stream().map(WindTask::getId).collect(Collectors.toList());
        QueryFilter actorFilter = new QueryFilter()
                .setTaskIds(taskIds.toArray(new String[]{}));
        this.allTaskActors = this.commandContext.access().selectTaskActorList(actorFilter);
    }


    /**
     * 所有流程实例，包含子流程实例
     *
     */
    private void allOrderInstance(){
        String parentOrderId = this.wind().getWindOrder().getId();
        QueryFilter filter = new QueryFilter()
                .setParentId(parentOrderId);
        this.allOrders =  this.commandContext.access().selectOrderInstanceList(filter);
        this.allOrders.add(this.wind().getWindOrder());
    }



    void changeResume(){
        WindUser user = wind().getUser();
        String orderId = wind().getWindOrder().getId();
        //获取当前唯一一个任务
        Task task = wind().getCurNode().get(0);
        WindTask windTask = task.getWindTask();
        if(windTask != null){
            //获取该任务的执行履历
            String taskId = windTask.getId();
            QueryFilter filter = new QueryFilter()
                    .setTaskId(taskId);
            List<WindActHistory> windActHistories = this.commandContext.access().selectActiveHistoryList(filter);
            if(!windActHistories.isEmpty()){
                //更新执行履历
                WindActHistory actHistory = windActHistories.get(0);
                actHistory.setActorId(user.getUserId())
                        .setActorName(user.getUserName())
                        .setApproveTime(TimeHelper.nowDate())
                        .setSuggest(wind().getSuggest())
                        .setOperate(wind().getOperate().name())
                        .setSubmitUserVariable(JsonHelper.toJson(user))
                        .setSystem(wind().getSystem());
                //更新
                this.commandContext.access().updateActiveHistory(actHistory);
            }

            //查询当前流程下所有的执行履历
            QueryFilter actFilter = new QueryFilter()
                    .setOrderId(orderId);
            List<WindActHistory> actHistories = this.commandContext.access().selectActiveHistoryList(actFilter);
            //删除执行履历
            this.commandContext.access().removeActiveHistoryByOrderId(orderId);
            //将执行履历添加到完毕履历中
            this.commandContext.access().insertCompleteHistoryList(actHistories);
        }

    }


    void  withdrawAndCompleteCurNode(){
        //获取唯一一个任务
        List<WindTask> windTasks = wind().getAllTasks();
        WindTask windTask = windTasks.get(0);
        Task task = buildCurNodeConfig(windTask.getTaskName(),windTask);

        //如果任务类型为分支中，或者串签，会签则禁止完结
        NodeModel nodeModel = task.getTaskNode();
        if(nodeModel instanceof TaskNode){
            Assert.isTrueError(WITH_DRAW_NOT_SUPPORT,((TaskNode) nodeModel).inForkJoin()
                    || ((TaskNode) nodeModel).jointly() || ((TaskNode) nodeModel).strand());
        }

        //添加到执行数据中
        wind().getCurNode().add(task);
    }


    WindOrder buildWindOrder(String orderId){
        QueryFilter filter = new QueryFilter()
                .setOrderId(orderId)
                .setOrderType(OrderType.main.name());
        List<WindOrder> windOrders = this.commandContext.access().selectOrderInstanceList(filter);
        Assert.notEmptyError(ORDER_NOT_EXISTS,windOrders,orderId);
        WindOrder windOrder = windOrders.get(0);
        //暂停状态的流程不可操作
        Assert.isTrueError(ORDER_IS_STOP_STATUS,windOrder.getStatus().equals(OrderStatus.stop.name()));
        return windOrder;
    }

}
